use anyhow::{anyhow, Ok, Result};
use std::{
    sync::mpsc::{self, channel},
    thread::{self, sleep},
    time::Duration,
};

const NUM_PRODUCERS: usize = 4;

#[derive(Debug)]
#[allow(dead_code)]
struct Msg {
    index: usize,
    value: usize,
}

impl Msg {
    fn new(index: usize, value: usize) -> Self {
        Self { index, value }
    }
}
fn main() -> Result<()> {
    let (tx, rx) = channel();

    for index in 0..NUM_PRODUCERS {
        let ctx = tx.clone();
        thread::spawn(move || producer(index, ctx));
    }
    drop(tx);

    let consumer = thread::spawn(move || {
        for msg in rx {
            println!("consumer:{:?}", msg);
        }
        println!("consumer stop");
        42
    });
    let value = consumer
        .join()
        .map_err(|e| anyhow!("Thread join error:{:?}", e))?;
    println!("{value}");
    Ok(())
}

fn producer(index: usize, tx: mpsc::Sender<Msg>) -> Result<()> {
    loop {
        let value = rand::random::<usize>();
        tx.send(Msg::new(index, value))?;
        let sleep_time = rand::random::<u8>() as u64 * 10;
        sleep(Duration::from_millis(sleep_time));
        let r = rand::random::<u8>() as u32;
        if r % 10 == 0 {
            println!("producer:{r},idx:{index} stop");
            break;
        }
    }
    Ok(())
}
